package com.steel.yfmall.cloud.assistant.view.impl;

import com.alibaba.fastjson.JSONObject;
import com.steel.yfmall.cloud.assistant.utils.zg.ZgViewUtil;
import com.steel.yfmall.cloud.assistant.view.ReachRegionBeanService;
import com.steel.yfmall.cloud.assistant.zg.ZgSOService;
import com.steel.yfmall.cloud.assistant.dto.para.view.ParaReachRegionBean;
import com.steel.yfmall.cloud.assistant.dto.zg.SynZgResult;
import com.steel.yfmall.cloud.assistant.dto.zg.ZgSOResultBean;
import com.steel.yfmall.cloud.assistant.dto.zg.ZgViewBean;
import com.steel.yfmall.cloud.assistant.po.view.ReachRegionBean;
import com.steel.yfmall.cloud.assistant.po.view.ReachRegionBeanExample;
import com.steel.yfmall.cloud.assistant.po.view.ReachRegionBeanExample.Criteria;
import com.steel.yfmall.cloud.assistant.view.mapper.ReachRegionBeanMapper;
import com.steel.yfmall.cloud.components.utils.base.APIMsgBean;
import com.steel.yfmall.cloud.components.utils.base.Pages;
import com.steel.yfmall.cloud.components.utils.base.ResponseCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * 终到地区业务逻辑处理类 主要包含终到地区代码、终到地区名称内容
 *
 * @author jia chang bao
 * @date 2020/11/5 10:16
 */
@Service
@Slf4j
public class ReachRegionBeanServiceImpl implements ReachRegionBeanService {

    @Resource
    private ReachRegionBeanMapper reachRegionBeanMapper;

    @Resource
    private ZgSOService zgSOService;

    /**
     * 获取终到地区表总条数, 可以有条件或无条件
     *
     * @param reachRegionBean 终到地区业务条件
     * @return long 总条数
     */
    @Override
    public long getReachRegionCount(ParaReachRegionBean reachRegionBean) {
        ReachRegionBeanExample reachRegionBeanExample = new ReachRegionBeanExample();
        Criteria criteria = reachRegionBeanExample.createCriteria();
        //判断入参对象是否为空
        if (!ObjectUtils.isEmpty(reachRegionBean)) {
            getSearchData(criteria, reachRegionBean);
        }
        long result_count_int = reachRegionBeanMapper.countByExample(reachRegionBeanExample);
        return result_count_int;
    }

    /***
     * 根据条件分页查询终到地区信息（分页）
     * @param paraReachRegionBean 终到地区业务条件
     * @return Pages<ReachRegionBean> 分页信息
     */
    @Override
    public Pages<ReachRegionBean> getReachRegionCountOfPage(ParaReachRegionBean paraReachRegionBean) {
        Pages<ReachRegionBean> returnBean = new Pages<>();
        //判断入参是否为空
        if (ObjectUtils.isEmpty(paraReachRegionBean)) {
            return returnBean;
        }
        ReachRegionBeanExample reachRegionBeanExample = new ReachRegionBeanExample();
        Criteria criteria = reachRegionBeanExample.createCriteria();

        //设置查询条件呢
        getSearchData(criteria, paraReachRegionBean);
        //总页数
        long result_count_int = reachRegionBeanMapper.countByExample(reachRegionBeanExample);
        //设置分页信息
        returnBean.paging(paraReachRegionBean.getCurrentPage(), paraReachRegionBean.getPageSize(), result_count_int);
        reachRegionBeanExample.limit(returnBean.getStartPosition(), paraReachRegionBean.getPageSize());
        //判断是否有排序规则
        if (StringUtils.isNotBlank(paraReachRegionBean.getOrderByValue())) {
            reachRegionBeanExample.setOrderByClause(paraReachRegionBean.getOrderByValue());
        }
        //查询得到分页后的数
        List<ReachRegionBean> reachRegionBeans = reachRegionBeanMapper.selectByExample(reachRegionBeanExample);
        //封装返回
        returnBean.setList(reachRegionBeans);
        return returnBean;
    }

    /***
     * 根据条件不分页查询终到地区信息（不分页）
     * @param paraReachRegionBean 终到地区业务条件
     * @return
     */
    @Override
    public List<ReachRegionBean> getReachRegionCountOfList(ParaReachRegionBean paraReachRegionBean) {
        ReachRegionBeanExample reachRegionBeanExample = new ReachRegionBeanExample();
        Criteria criteria = reachRegionBeanExample.createCriteria();

        //判断入参是否为空
        if (ObjectUtils.isEmpty(paraReachRegionBean)) {
            return null;
        }

        getSearchData(criteria, paraReachRegionBean);
        List<ReachRegionBean> reachRegionBeans = reachRegionBeanMapper.selectByExample(reachRegionBeanExample);
        return reachRegionBeans;
    }

    /**
     * 批量新增
     *
     * @param reachRegionBean 终到地区业务条件
     * @return 受影响条数
     */
    @Override
    public int addReachRegionCountOfList(List<ReachRegionBean> reachRegionBean) {
        return reachRegionBeanMapper.batchInsertByList(reachRegionBean);
    }

    /**
     * 根据条件修改终到地区信息
     *
     * @param reachRegionBean 终到地区业务条件
     * @return 受影响条数
     */
    @Override
    public int updateReachRegion(ReachRegionBean reachRegionBean) {
        ReachRegionBeanExample reachRegionBeanExample = new ReachRegionBeanExample();
        //使用id和area_no联合修改终到地区名称
        reachRegionBeanExample.createCriteria().andAreaNoEqualTo(reachRegionBean.getAreaNo()).andIdEqualTo(reachRegionBean.getId());
        //设置修改时间
        reachRegionBean.setUpdateTime(new Date());
        reachRegionBean.setCreateTime(null);
        return reachRegionBeanMapper.updateByExampleSelective(reachRegionBean, reachRegionBeanExample);
    }

    /**
     * 根据条件删除终到地区信息
     *
     * @param paraReachRegionBean 终到地区业务条件
     * @return 受影响条数
     */
    @Override
    public int deleteReachRegion(ParaReachRegionBean paraReachRegionBean) {
        //条件为空时不删除
        if (ObjectUtils.isEmpty(paraReachRegionBean)) {
            return 0;
        }
        ReachRegionBeanExample reachRegionBeanExample = new ReachRegionBeanExample();
        Criteria criteria = reachRegionBeanExample.createCriteria();
        getSearchData(criteria, paraReachRegionBean);

        return reachRegionBeanMapper.deleteByExample(reachRegionBeanExample);
    }

    /**
     * 批量删除终到地区信息
     *
     * @param paraReachRegionBean 终到地区业务条件
     * @return 受影响条数
     */
    @Override
    public int deleteReachRegionOfList(List<ParaReachRegionBean> paraReachRegionBean) {
        //判断是否有数据
        if (CollectionUtils.isEmpty(paraReachRegionBean)) {
            return 0;
        }
        ReachRegionBeanExample reachRegionBeanExample = new ReachRegionBeanExample();
        //使用id和area_no联合修改终到地区名称
        Criteria criteria = reachRegionBeanExample.createCriteria();
        //存储条件，integer为主键，string为终到地区编码，
        Map<Integer, String> conditionMap = new HashMap<>();
        for (ParaReachRegionBean paraReachRegionBean1 : paraReachRegionBean) {
            conditionMap.put(paraReachRegionBean1.getId(), paraReachRegionBean1.getAreaNo());
        }
        criteria.andIdIn(new ArrayList<>(conditionMap.keySet()));
        return reachRegionBeanMapper.deleteByExample(reachRegionBeanExample);
    }

    /**
     * 同步方法
     *
     * @return
     * @param zgViewBean
     */
    @Override
    public APIMsgBean synchronizationZgReachRegion(ZgViewBean zgViewBean) {
        APIMsgBean serviceDataBean = new APIMsgBean();
        //默认失败
        serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean("数据同步失败"));
        //参数校验
        String msg = checkData(zgViewBean);
        if (!StringUtils.isBlank(msg)) {
            serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean(msg));
            return serviceDataBean;
        }

        SynZgResult synZgResult = new SynZgResult();
        //同步计时开始
        long begintime = System.currentTimeMillis();
        ZgSOResultBean viewData = zgSOService.getViewData(zgViewBean);
        //同步计时结束
        long endtime = System.currentTimeMillis();
        long costTime = (endtime - begintime);

        //请求中冠成功后
        if ("Y".equals(viewData.getIsSuccess())) {
            List<ReachRegionBean> reachRegionBeans = null;
            try {
                reachRegionBeans = JSONObject.parseArray(viewData.getData(), ReachRegionBean.class);
            } catch (Exception e) {
                serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean("终到地区数据同步解析出错"));
                log.error("终到地区数据同步解析出错，错误信息：" ,e);
            }
            //检查数据库是否有重复,过滤掉重复信息并设置创建、更新、版本信息
            reachRegionBeans = checkDataBase(reachRegionBeans);
            if (!CollectionUtils.isEmpty(reachRegionBeans)) {
                //批量新增
                int i = addReachRegionCountOfList(reachRegionBeans);
                if (i > 0) {
                    //设置同步所用时间
                    synZgResult.setSynTime(String.valueOf(costTime));
                    //设置同步条数
                    synZgResult.setCountNum(i);
                    //设置同步状态
                    synZgResult.setState(true);
                    serviceDataBean.setSoaStateBean(ResponseCode.buildEnumSuccessSOAStateBean("数据同步成功"));
                    serviceDataBean.setData(synZgResult);
                    //日志记录
                    log.info("终到地区数据同步成功，本次同步" + i + "条数据,耗时" + costTime + "毫秒");
                }
            } else {
                log.info("无数据同步");
                serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean("无数据同步"));
            }
        } else {
            serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean(viewData.getMsg()));
        }
        //递归同步
        try {
            //起始页
            int startPage = Integer.parseInt(zgViewBean.getPageNum());
            //判断是否还有数据
            if (startPage < viewData.getZgpageData().getPages()) {
                startPage++;
                zgViewBean.setPageNum(String.valueOf(startPage));
                synchronizationZgReachRegion(zgViewBean);
            }
        } catch (Exception e) {
            serviceDataBean.setSoaStateBean(ResponseCode.buildEnumErrorSOAStateBean("终到地区数据递归同步出错"));
            log.error("终到地区数据递归同步出错，错误信息：" , e);
        }
        return serviceDataBean;
    }

    /***
     * 检查数据库中数据是否存在，将不存在的数据返回，过滤掉重复的数据
     * @param reachRegionBeans 需要检查的数据
     * @return List<ReachRegionBean> 过滤剩余的数据
     */
    private List<ReachRegionBean> checkDataBase(List<ReachRegionBean> reachRegionBeans) {
        if (CollectionUtils.isEmpty(reachRegionBeans)) {
            return null;
        }
        ReachRegionBeanExample reachRegionBeanExample = new ReachRegionBeanExample();
        Criteria criteria = reachRegionBeanExample.createCriteria();
        //提取终到地区编码和库中数据做比较，如果重复则判定为重复数据。
        Map<String, ReachRegionBean> reachRegionBeanMap = new HashMap<>();
        for (ReachRegionBean reachRegionBean : reachRegionBeans) {
            reachRegionBeanMap.put(reachRegionBean.getAreaNo(), reachRegionBean);
        }
        //查询数据库是否有重复数据
        Set<String> strings = reachRegionBeanMap.keySet();
        criteria.andAreaNoIn(new ArrayList<>(strings));
        List<ReachRegionBean> dbReachRegionBean = reachRegionBeanMapper.selectByExample(reachRegionBeanExample);
        List<ReachRegionBean> oldReachRegionBean = new ArrayList<>();
        //比对是否用有重复数
        for (ReachRegionBean reachRegionBean : dbReachRegionBean) {
            String areaNo = reachRegionBean.getAreaNo();
            if (reachRegionBeanMap.containsKey(areaNo)) {
                oldReachRegionBean.add(reachRegionBeanMap.get(areaNo));
                reachRegionBeanMap.remove(areaNo);
            }
        }
        reachRegionBeans = new ArrayList<>(reachRegionBeanMap.values());
        for (int i = 0; i < reachRegionBeans.size(); i++) {
            reachRegionBeans.get(i).setCreateTime(new Date());
            reachRegionBeans.get(i).setUpdateTime(new Date());
            reachRegionBeans.get(i).setVersionInt(0);
        }
        //当存在重复数据时
        if (!CollectionUtils.isEmpty(oldReachRegionBean)) {
            //复用对象
            reachRegionBeanMap.clear();
            for (ReachRegionBean reachRegionBean : oldReachRegionBean) {
                reachRegionBeanMap.put(reachRegionBean.getAreaNo(), reachRegionBean);
            }
            //细致比对取出差异数据然后线程修改
            List<ReachRegionBean> reachRegionBeanList = equlstDateChange(reachRegionBeanMap);
            if (!CollectionUtils.isEmpty(reachRegionBeanList)) {
                asynchronousUpDate asynchronousUpDate = new asynchronousUpDate(reachRegionBeanList);
                new Thread(asynchronousUpDate).start();
            }
        }
        //返回不重复的数据
        return reachRegionBeans;
    }

    /**
     * @param reachRegionBeanMap 重复的数据
     * @return List<ReachRegionBean> 重复且有差异的信息
     * @Description 校验比较返回重复且有差异的的信息
     * @author jia chang bao
     * @date 2020/11/9 17:17
     */
    private List<ReachRegionBean> equlstDateChange(Map<String, ReachRegionBean> reachRegionBeanMap) {
        //如果对象为空就直接结束
        if (reachRegionBeanMap.isEmpty()) {
            return null;
        }
        //条件
        ReachRegionBeanExample reachRegionBeanExample = new ReachRegionBeanExample();
        Criteria criteria = reachRegionBeanExample.createCriteria();
        //将终到地区代码条件
        Set<String> strings = reachRegionBeanMap.keySet();
        criteria.andAreaNoIn(new ArrayList<>(strings));
        //查询出重复的数据用于细致比对
        List<ReachRegionBean> dbReachRegionBean = reachRegionBeanMapper.selectByExample(reachRegionBeanExample);
        //用来存储重复且有差异的数据
        List<ReachRegionBean> reachRegionBeanList = new ArrayList<>();
        //用数据库中的数据和同步过来的数据进行比较
        for (ReachRegionBean reachRegionBean : dbReachRegionBean) {
            String postNo = reachRegionBean.getAreaNo();
            //如果存在相同的终到地区编码
            if (reachRegionBeanMap.containsKey(postNo)) {
                ReachRegionBean reachRegionBean1 = reachRegionBeanMap.get(postNo);
                //当终到地区 数据存在差异时判定为差异数据
                if (!reachRegionBean1.getAreaName().equals(reachRegionBean.getAreaName())) {
                    reachRegionBean1.setId(reachRegionBean.getId());
                    reachRegionBean1.setUpdateTime(new Date());
                    reachRegionBean1.setVersionInt(reachRegionBean.getVersionInt() + 1);
                    reachRegionBeanList.add(reachRegionBean1);
                }
            }
        }
        return reachRegionBeanList;
    }

    /**
     * 线程异步修改重复的数
     */
    private class asynchronousUpDate implements Runnable {
        List<ReachRegionBean> oldReachRegionBean;

        public asynchronousUpDate(List<ReachRegionBean> oldReachRegionBean) {
            this.oldReachRegionBean = oldReachRegionBean;
        }

        @Override
        public void run() {
            try {
                if (!CollectionUtils.isEmpty(oldReachRegionBean)) {
                    //记录总需改数据
                    int i = 0;
                    long begintime = System.currentTimeMillis();
                    for (ReachRegionBean reachRegionBean : oldReachRegionBean) {
                        i += updateReachRegion(reachRegionBean);
                    }
                    long endtime = System.currentTimeMillis();
                    long costTime = (endtime - begintime);
                    log.info("异步修改地区同步差异信息成功，本次修改" + i + "条数据，耗时" + costTime + "毫秒");
                }
            } catch (Exception e) {
                log.error("同步后的差异数据修改失败，错误原因：" , e);
            }
        }
    }

    /**
     * sql拼接
     *
     * @param criteria        sql拼接
     * @param reachRegionBean 参数
     */
    private void getSearchData(Criteria criteria, ParaReachRegionBean reachRegionBean) {
        // ID
        if (reachRegionBean.getId() != null && reachRegionBean.getId() > 0) {
            criteria.andIdEqualTo(reachRegionBean.getId());
        }
        // 终到地区代码
        if (StringUtils.isNotBlank(reachRegionBean.getAreaNo())) {
            criteria.andAreaNoEqualTo(reachRegionBean.getAreaNo());
        }
        //终到地区名称
        if (StringUtils.isNotBlank(reachRegionBean.getAreaName())) {
            criteria.andAreaNameEqualTo(reachRegionBean.getAreaName());
        }
        //创建时间
        if (reachRegionBean.getCreateTime() != null) {
            criteria.andCreateTimeEqualTo(reachRegionBean.getCreateTime());
        }
        //版本号
        if (reachRegionBean.getVersionInt() != null && reachRegionBean.getVersionInt() > 0) {
            criteria.andVersionIntEqualTo(reachRegionBean.getVersionInt());
        }
        //修改时间
        if (reachRegionBean.getUpdateTime() != null) {
            criteria.andUpdateTimeEqualTo(reachRegionBean.getUpdateTime());
        }
    }

    /**
     * 中冠视图请求的参数校验
     *
     * @param zgViewBean 视图名称
     * @return 校验结果
     */
    private String checkData(ZgViewBean zgViewBean) {
        String msg = "";
        if (!StringUtils.isNotBlank(zgViewBean.getMethod())) {
            msg += "请求方法不能为空";
        }
        if (!StringUtils.isNotBlank(zgViewBean.getViewId())) {
            msg += "请求的视图不能为空";
        }
        if (!StringUtils.isNotBlank(zgViewBean.getPageNum())) {
            msg += "请求的页码不能为空";
        }
        return msg;
    }

}
